home *** CD-ROM | disk | FTP | other *** search
/ Linux Cubed Series 7: Sunsite / Linux Cubed Series 7 - Sunsite Vol 1.iso / system / admin / linuxcon.000 / linuxcon / linuxconf-1.6 / netconf / ppp.c < prev    next >
C/C++ Source or Header  |  1996-07-05  |  22KB  |  901 lines

  1. #include <stdio.h>
  2. #include <stdlib.h>
  3. #include <string.h>
  4. #include <unistd.h>
  5. #include <limits.h>
  6. #include <signal.h>
  7. #include "../misc/confdb.h"
  8. #include "netconf.h"
  9. #include "../userconf/userconf.h"
  10. #include "../paths.h"
  11. #include "netconf.m"
  12.  
  13. static char ATZOK[]="ATZ OK ATDT";
  14. #define TYPE_PPP_LOGIN    0
  15. #define TYPE_PPP_PAP    1
  16. #define TYPE_PPP_CHAP    2
  17. #define TYPE_SLIP        3
  18. #define TYPE_PLIP1        4
  19. #define TYPE_PLIP2        5
  20.  
  21. static NETCONF_HELP_FILE help_ppp ("ppp");
  22.  
  23. static CONFIG_FILE f_ppp (ETC_PPP_CONF_PPP
  24.     ,help_ppp
  25.     ,CONFIGF_OPTIONNAL|CONFIGF_MANAGED
  26.     ,"root","root",0600);
  27. // File used to store argument of pppd
  28. static CONFIG_FILE f_pppargs (VAR_RUN_PPPD_ARGS
  29.     ,help_ppp
  30.     ,CONFIGF_GENERATED
  31.     ,"root","root",0600);
  32. static CONFIG_FILE f_ppp0 (VAR_RUN_PPP0_PID
  33.     ,help_ppp
  34.     ,CONFIGF_OPTIONNAL
  35.     ,"root","root",0600);
  36.  
  37.  
  38. /* #Specification: PPP & SLIP / management
  39.     All configuration information is store in the file
  40.     /etc/ppp/conf.ppp. This file is a CONFDB file, with
  41.     the same format as /etc/conf.linuxconf.
  42.  
  43.     The information for all channels are stored in this file
  44.  
  45.     There are record identifying the channels
  46.  
  47.     #
  48.     .channel name1
  49.     .channel name2
  50.     #
  51.  
  52.     And then, for each channel
  53.  
  54.     #
  55.     name1.login login
  56.     name1.passwd password
  57.     name1.phone phone
  58.     #
  59.  
  60.     and so on.
  61. */
  62. struct LK_STR{
  63.     const char *key;
  64.     SSTRING *str;
  65.     const char *defval;
  66. };
  67. struct LK_INT{
  68.     const char *key;
  69.     int *num;
  70.     int defval;
  71. };
  72. struct LK_CHAR{
  73.     const char *key;
  74.     char *num;
  75.     char defval;
  76. };
  77.  
  78. class PPPONE{
  79.     SSTRING name;        // Symbolic name of the configuration
  80.     SSTRING phone;
  81.     SSTRING login;
  82.     SSTRING passwd;
  83.     SSTRING loginkey;    // String required before sending login
  84.                         // Normally ogin:
  85.     SSTRING passwdkey;    // String required before sending the password
  86.                         // Normally assword:
  87.     SSTRING loginok;    // optionnal confirmation string
  88.                         // telling the passwd was good
  89.     SSTRING loginfail;    // optionnal string identifying a login failure
  90.                         // (password was wrong)
  91.     SSTRING loginchat;    // Custom login chat in case the standard one
  92.                         // fail.
  93.     SSTRING device;
  94.     SSTRING modeminit;
  95.     char type;    // TYPE_xxxx
  96.     char defaultroute;
  97.     char modem;    // Modem controls
  98.     char lock;    // Set standard lock file
  99.     char proxyarp;    // Establish proxyarp when connecting
  100.     int mru;
  101.     int mtu;
  102.     int baud;
  103.     int idletime;
  104.     char dbgppp;
  105.     char dbgchat;
  106.     SSTRING options;    // pppd options which are not
  107.                 // handled by this program
  108.     SSTRING asyncmap;    // One specific important option of
  109.                 // pppd
  110.     SSTRING ourip;        // Optionnal IP numbers
  111.     SSTRING remoteip;
  112.     SSTRING lcpecho;
  113.     LK_STR strs[20];
  114.     LK_INT nums[20];
  115.     LK_CHAR chars[20];
  116.     /*~PROTOBEG~ PPPONE */
  117. public:
  118.     PPPONE (CONFDB&cfg, const char *_name);
  119.     int connect (int fore);
  120. private:
  121.     int connect_plip (void);
  122.     int connect_ppp (int fore);
  123.     int connect_slip (int);
  124. protected:
  125.     void del (CONFDB&cfg, const char *_name);
  126. public:
  127.     int disconnect (void);
  128. private:
  129.     int disconnect_plip (void);
  130. public:
  131.     int disconnect_ppp (void);
  132. private:
  133.     int disconnect_slip (void);
  134. public:
  135.     int edit (CONFDB&cfg);
  136. private:
  137.     int lcpecho_parse (int &delay, int &retry);
  138.     int lcpecho_valid (void);
  139. public:
  140.     int save (CONFDB&cfg);
  141. private:
  142.     void setuptbdb (void);
  143. public:
  144.     /*~PROTOEND~ PPPONE */
  145. };
  146.  
  147. static char CHANNEL[]="channel";
  148. static char PHONE[]="phone";
  149. static char LOGIN[]="login";
  150. static char PASSWD[]="passwd";
  151. static char LOGINKEY[]="loginkey";
  152. static char PASSWDKEY[]="passwdkey";
  153. static char LOGINOK[]="loginok";
  154. static char LOGINFAIL[]="loginfail";
  155. static char LOGINCHAT[]="loginchat";
  156. static char DEVICE[]="device";
  157. static char MODEMINIT[]="modeminit";
  158. static char TYPE[]="type";
  159. static char LOCK[]="lock";
  160. static char MODEM[]="modem";
  161. static char DEFAULTROUTE[]="defaultroute";
  162. static char PROXYARP[]="proxyarp";
  163. static char MRU[]="mru";
  164. static char MTU[]="mtu";
  165. static char BAUD[]="baud";
  166. static char IDLETIME[]="idletime";
  167. static char DBGPPP[]="dbgppp";
  168. static char DBGCHAT[]="dbgchat";
  169. static char OPTIONS[]="options";
  170. static char ASYNCMAP[]="asyncmap";
  171. static char OURIP[]="ourip";
  172. static char REMOTEIP[]="remoteip";
  173. static char LCPECHO[]="lcpecho";
  174. /*
  175.     Initialise 3 tables to simplify loading/clearing and saving
  176. */
  177. PRIVATE void PPPONE::setuptbdb()
  178. {
  179.     memset (strs,0,sizeof(strs));
  180.     memset (chars,0,sizeof(chars));
  181.     memset (nums,0,sizeof(nums));
  182.  
  183.     strs[0].key = PHONE;
  184.     strs[0].str = ☎
  185.  
  186.     strs[1].key = LOGIN;    
  187.     strs[1].str = &login;    
  188.  
  189.     strs[2].key = PASSWD;
  190.     strs[2].str = &passwd;
  191.  
  192.     strs[3].key = DEVICE;
  193.     strs[3].str = &device;
  194.  
  195.     strs[4].key = MODEMINIT;
  196.     strs[4].str = &modeminit;
  197.     strs[4].defval = ATZOK;
  198.  
  199.     strs[5].key = OPTIONS;
  200.     strs[5].str = &options;
  201.  
  202.     strs[6].key = ASYNCMAP;
  203.     strs[6].str = &asyncmap;
  204.     strs[6].defval = "0";
  205.  
  206.     strs[7].key = OURIP;
  207.     strs[7].str = &ourip;
  208.  
  209.     strs[8].key = REMOTEIP;
  210.     strs[8].str = &remoteip;
  211.  
  212.     strs[9].key = LOGINOK;
  213.     strs[9].str = &loginok;
  214.  
  215.     strs[10].key = LOGINCHAT;
  216.     strs[10].str = &loginchat;
  217.  
  218.     strs[11].key = LOGINFAIL;
  219.     strs[11].str = &loginfail;
  220.  
  221.     strs[12].key = LOGINKEY;
  222.     strs[12].str = &loginkey;
  223.     strs[12].defval = "ogin:--ogin:";
  224.  
  225.     strs[13].key = PASSWDKEY;
  226.     strs[13].str = &passwdkey;
  227.     strs[13].defval = "assword:";
  228.  
  229.     strs[14].key = LCPECHO;
  230.     strs[14].str = &lcpecho;
  231.     strs[14].defval = "";
  232.  
  233.     strs[15].key = NULL;
  234.  
  235.     chars[0].key = TYPE;
  236.     chars[0].num = &type;
  237.     chars[0].defval = 0;
  238.  
  239.     chars[1].key = MODEM;
  240.     chars[1].num = &modem;
  241.     chars[1].defval = 1;
  242.  
  243.     chars[2].key = DEFAULTROUTE;
  244.     chars[2].num = &defaultroute;
  245.     chars[2].defval = 1;
  246.  
  247.     chars[3].key = LOCK;
  248.     chars[3].num = &lock;
  249.     chars[3].defval = 1;
  250.  
  251.     chars[4].key = DBGPPP;
  252.     chars[4].num = &dbgppp;
  253.     chars[4].defval = 0;
  254.  
  255.     chars[5].key = DBGCHAT;
  256.     chars[5].num = &dbgchat;
  257.     chars[5].defval = 0;
  258.  
  259.     chars[6].key = PROXYARP;
  260.     chars[6].num = &proxyarp;
  261.     chars[6].defval = 0;
  262.  
  263.     chars[7].key = NULL;
  264.  
  265.  
  266.     nums[0].key = BAUD;
  267.     nums[0].num = &baud;
  268.     nums[0].defval = 38400;
  269.  
  270.     nums[1].key = MRU;
  271.     nums[1].num = &mru;
  272.     nums[1].defval = 1500;
  273.  
  274.     nums[2].key = IDLETIME;
  275.     nums[2].num = &idletime;
  276.     nums[2].defval = 0;
  277.  
  278.     nums[3].key = MTU;
  279.     nums[3].num = &mtu;
  280.     nums[3].defval = 0;
  281.  
  282.     nums[4].key = NULL;
  283. }
  284.  
  285. PUBLIC PPPONE::PPPONE(CONFDB &cfg, const char *_name)
  286. {
  287.     setuptbdb();
  288.     #if 0
  289.         type = 0;
  290.         baud = 38400;
  291.         lock = 1;
  292.         mru = 1500;
  293.         mtu = 0;
  294.         modem = 1;
  295.         idletime = 0;
  296.         proxyarp = 0;
  297.         modeminit.setfrom (ATZOK);
  298.         defaultroute = 1;
  299.         dbgppp = 0;
  300.         dbgchat = 0;
  301.         asyncmap.setfrom ("0");
  302.     #endif
  303.     if (_name != NULL){
  304.         name.setfrom (_name);
  305.         for (LK_STR *ps = strs; ps->key != NULL; ps++){
  306.             ps->str->setfrom (cfg.getval(_name,ps->key
  307.                 ,ps->defval));
  308.         }
  309.         for (LK_INT *pn = nums; pn->key != NULL; pn++){
  310.             *pn->num = cfg.getvalnum(_name,pn->key
  311.                 ,pn->defval);
  312.         }
  313.         for (LK_CHAR *pc = chars; pc->key != NULL; pc++){
  314.             *pc->num = cfg.getvalnum(_name,pc->key
  315.                 ,pc->defval);
  316.         }
  317.     }else{
  318.         for (LK_STR *ps = strs; ps->key != NULL; ps++){
  319.             ps->str->setfrom (ps->defval);
  320.         }
  321.         for (LK_INT *pn = nums; pn->key != NULL; pn++){
  322.             *pn->num = pn->defval;
  323.         }
  324.         for (LK_CHAR *pc = chars; pc->key != NULL; pc++){
  325.             *pc->num = pc->defval;
  326.         }
  327.     }
  328. }
  329.  
  330. /*
  331.     Update the CONFDB object and save it on disk
  332. */
  333. PUBLIC int PPPONE::save(CONFDB &cfg)
  334. {
  335.     const char *_name = name.get();
  336.     SSTRINGS lst;
  337.     cfg.getall ("",CHANNEL,lst,1);
  338.     if (lst.lookup(name.get())==-1){
  339.         lst.add (new SSTRING(name));
  340.         cfg.replace ("",CHANNEL,lst);
  341.     }
  342.     for (LK_STR *ps = strs; ps->key != NULL; ps++){
  343.         cfg.replace (_name,ps->key,*ps->str);
  344.     }
  345.     for (LK_INT *pn = nums; pn->key != NULL; pn++){
  346.         cfg.replace (_name,pn->key,*pn->num);
  347.     }
  348.     for (LK_CHAR *pc = chars; pc->key != NULL; pc++){
  349.         cfg.replace (_name,pc->key,*pc->num);
  350.     }
  351.     return cfg.save();
  352. }
  353.  
  354. /*
  355.     Remove this configuration from the configuration file
  356. */
  357. PROTECTED void PPPONE::del(CONFDB &cfg, const char *_name)
  358. {
  359.     if (_name[0] != '\0'){
  360.         SSTRINGS lst;
  361.         cfg.getall ("",CHANNEL,lst,1);
  362.         int pos = lst.lookup(_name);
  363.         if (pos != -1){
  364.             lst.remove_del (lst.getitem(pos));
  365.             cfg.replace ("",CHANNEL,lst);
  366.         }
  367.         for (LK_STR *ps = strs; ps->key != NULL; ps++){
  368.             cfg.removeall (_name,ps->key);
  369.         }
  370.         for (LK_INT *pn = nums; pn->key != NULL; pn++){
  371.             cfg.removeall (_name,pn->key);
  372.         }
  373.         for (LK_CHAR *pc = chars; pc->key != NULL; pc++){
  374.             cfg.removeall (_name,pc->key);
  375.         }
  376.     }
  377. }
  378.  
  379. /*
  380.     Check if the configuration name exist
  381. */
  382. static int ppp_exist (CONFDB &cfg, const SSTRING &name)
  383. {
  384.     SSTRINGS lst;
  385.     cfg.getall ("",CHANNEL,lst,0);
  386.     return lst.lookup(name.get()) != -1;
  387. }
  388.  
  389. /*
  390.     Add a baud rate field in a dialog with standard values
  391. */
  392. void baud_setfield (
  393.     int baud,
  394.     SSTRING &baudstr,
  395.     DIALOG &dia)
  396. {
  397.     char msg[10];
  398.     baudstr.setfrom (baud);
  399.     FIELD_COMBO    *comb = dia.newf_combo (MSG_U(F_BAUD,"Baud rate"),baudstr);
  400.     static short int tb[]={
  401.         3,6,12,24,48,96,
  402.         192,384,576,1152
  403.     };
  404.     for (unsigned i=0; i<sizeof(tb)/sizeof(tb[0]); i++){
  405.         sprintf (msg,"%d00",tb[i]);
  406.         comb->addopt (msg);
  407.     }
  408. }
  409.  
  410. void serial_setfield (
  411.     SSTRING &device,
  412.     DIALOG &dia)
  413. {
  414.     FIELD_COMBO *comb = dia.newf_combo  (MSG_U(F_SERIALDEF
  415.         ,"Serial device"),device);
  416.     comb->addopt ("/dev/cua0",MSG_U(F_FIRSTCOM,"first standard serial port COM1"));
  417.     comb->addopt ("/dev/cua1",MSG_U(F_SECONDCOM,"Second standard serial port COM2"));
  418.     comb->addopt ("/dev/ttyS0",MSG_U(F_COM1M,"COM1 when using mgetty"));
  419.     comb->addopt ("/dev/ttyS1",MSG_U(F_COM2M,"COM2 when using mgetty"));
  420. }
  421.  
  422. /*
  423.     Parse the lcpecho field (delay,retry).
  424.     Return -1 if any error, 0 if empty, 1 if a value pair is supplied
  425. */
  426. PRIVATE int PPPONE::lcpecho_parse(int &delay, int &retry)
  427. {
  428.     int ret = -1;
  429.     delay = retry = 0;
  430.     if (lcpecho.is_empty()){
  431.         ret = 0;
  432.     }else{
  433.         const char *str = lcpecho.get();
  434.         delay = atoi(str);
  435.         const char *pt = strchr(str,',');
  436.         if (pt != NULL){
  437.             retry = atoi(pt+1);
  438.             if (delay != 0 && retry != 0) ret = 1;
  439.         }
  440.     }
  441.     return ret;
  442. }
  443.  
  444. PRIVATE int PPPONE::lcpecho_valid()
  445. {
  446.     int d,r;
  447.     return lcpecho_parse (d,r)!=-1;
  448. }
  449.             
  450.         
  451.     
  452.  
  453. PUBLIC int PPPONE::edit (CONFDB &cfg)
  454. {
  455.     int ret = -1;
  456.     DIALOG dia;
  457.     SSTRING oldname (name);    
  458.     dia.newf_str  (MSG_U(F_PPPNAME,"Configuration name"),name);
  459.     dia.newf_radio (MSG_U(F_CONNECTTYPE,"Connection type"),type
  460.         ,TYPE_PPP_LOGIN
  461.         ,MSG_U(F_PPPLOGIN,"PPP using normal login account"));
  462.     dia.newf_radio ("",type,TYPE_PPP_PAP
  463.         ,MSG_U(F_PPPPAP,"PPP using PAP authentication"));
  464.     dia.newf_radio ("",type,TYPE_PPP_CHAP
  465.         ,MSG_U(F_PPPCHAP,"PPP using CHAP authentication"));
  466.     dia.newf_radio ("",type,TYPE_SLIP,MSG_U(F_SLIP,"SLIP"));
  467.     dia.newf_radio ("",type,TYPE_PLIP1
  468.         ,MSG_U(F_PLIP1,"PLIP1 (IP over printer port 1)"));
  469.     dia.newf_radio ("",type,TYPE_PLIP2
  470.         ,MSG_U(F_PLIP2,"PLIP2 (IP over printer port 2)"));
  471.     dia.newf_str (MSG_U(F_OURIP,"Our IP number(opt)"),ourip);
  472.     dia.newf_str (MSG_U(F_REMOTEIP,"Remote IP number(opt)"),remoteip);
  473.  
  474.     dia.newf_title ("",MSG_U(T_LOGINCHAT,"Login chat"));
  475.  
  476.     dia.newf_str  (MSG_U(F_LOGINKEY,"Expected login key"),loginkey);
  477.     dia.newf_str  (MSG_U(F_LOGIN,"login"),login);
  478.     dia.newf_str  (MSG_U(F_PASSWDKEY,"Expected password key"),passwdkey);
  479.     dia.newf_str  (MSG_U(F_PASSWORD,"Password"),passwd);
  480.     dia.newf_str  (MSG_U(F_LOGINOK,"Expected welcome (opt)"),loginok);
  481.     dia.newf_str  (MSG_U(F_LOGINFAIL,"Login fail key (opt)"),loginfail);
  482.     dia.newf_str  (MSG_U(F_LOGINCHAT,"Custom login chat (opt)"),loginchat);
  483.  
  484.     dia.newf_title ("",MSG_U(T_MODEM,"Modem specifications"));
  485.  
  486.     serial_setfield (device,dia);
  487.  
  488.     dia.newf_str (MSG_U(F_MODEMCHAT,"Modem initialisation"),modeminit);
  489.     dia.newf_str  (MSG_U(F_PHONE,"Phone"),phone);
  490.     dia.newf_chk ("",modem,MSG_U(F_MODEMCTRL,"Modem controls"));
  491.     dia.newf_chk ("",lock,MSG_U(F_LOCKFILE,"Lock file"));
  492.     SSTRING baudstr;
  493.     baud_setfield (baud,baudstr,dia);
  494.     dia.newf_title ("",MSG_U(T_FEATURES,"Features"));
  495.     dia.newf_chk ("",defaultroute,MSG_U(F_DEFROUTE,"Default route"));
  496.     dia.newf_chk ("",proxyarp
  497.         ,MSG_U(F_PROXYARP,"Proxy Arp (fake remote on local net)"));
  498.     dia.newf_num (MSG_U(F_IDLETIME,"Idle time"),idletime);
  499.     dia.newf_num (MSG_U(F_PPPMRU,"PPP MRU"),mru);
  500.     dia.newf_num (MSG_U(F_PPPMTU,"PPP MTU(opt)"),mtu);
  501.     dia.newf_chk ("",dbgppp,MSG_U(F_RUNPPPD,"Run pppd in debug mode"));
  502.     dia.newf_chk ("",dbgchat,MSG_U(F_RUNCHAT,"Run chat in debug mode"));
  503.     dia.newf_str (MSG_U(F_ASYNCMAP,"Async map"),asyncmap);
  504.     FIELD_COMBO *cecho = dia.newf_combo (MSG_U(F_LCPECHO,"LCP echo"),lcpecho);
  505.     cecho->addopt ("",MSG_U(F_NOLCPECHO,"Don't use LCP echo protocol"));
  506.     cecho->addopt ("15,3",MSG_U(F_ECHO15_3,"Send lcp echo every 15, hangup after 3 failures"));
  507.     dia.newf_str (MSG_U(F_OTHERPPP,"Other PPP options"),options);
  508.     int no = 0;
  509.     int extra_but = name.is_empty() ? 0 : MENUBUT_DEL;
  510.     while (1){
  511.         char title[100];
  512.         sprintf (title,MSG_U(T_ONEPPPCONF,"%s PPP/SLIP configuration")
  513.             ,name.is_empty() ? MSG_U(T_NEWPPP,"new") : name.get());
  514.         MENU_STATUS code = dia.edit (title
  515.             ,MSG_U(I_ONEPPPCONF,"One PPP, SLIP or PLIP configuration")
  516.             ,help_ppp
  517.             ,no
  518.             ,extra_but|MENUBUT_ACCEPT|MENUBUT_CANCEL);
  519.         if (code == MENU_CANCEL || code == MENU_ESCAPE){
  520.             break;
  521.         }else if (code == MENU_ACCEPT){
  522.             char buferr[2000];
  523.             buferr[0] = '\0';
  524.             baud = baudstr.getval();
  525.             if (!oldname.is_empty() && name.cmp(oldname)!=0){
  526.                 if (ppp_exist (cfg,name)){
  527.                     sprintf (buferr
  528.                         ,MSG_U(E_DUPCONF,"The configuration %s\n"
  529.                          "already exist\n"
  530.                          "Use another name\n\n")
  531.                         ,name.get());
  532.                 }
  533.             }
  534.             if (name.is_empty()){
  535.                 strcat (buferr,MSG_U(E_NEEDNAME,"You must supply\n"
  536.                     "a configuration name\n\n"));
  537.             }
  538.             if (device.is_empty()
  539.                 && type != TYPE_PLIP1
  540.                 && type != TYPE_PLIP2){
  541.                 strcat (buferr,MSG_U(E_NEEDDEV,"You must supply "
  542.                 "a device (/dev/xxxx)\n\n"));
  543.             }
  544.             if (!lcpecho_valid ()){
  545.                 strcat (buferr,MSG_U(E_LCPECHO,"You must supply a value pair\n"
  546.                     "    delay,retry for the LCP echo protocol"));
  547.             }
  548.             if (buferr[0] != '\0'){
  549.                 xconf_error (buferr);
  550.             }else{
  551.                 del(cfg,oldname.get());
  552.                 save (cfg);
  553.                 ret = 0;
  554.                 break;
  555.             }
  556.         }else if (code == MENU_DEL){
  557.             if (xconf_yesno(MSG_U(Q_DELETED,"Are you sure")
  558.                 ,MSG_U(I_DELETED,"This configuration will be\n"
  559.                  "deleted permanently")
  560.                 ,help_ppp)){
  561.                 dia.restore();
  562.                 del(cfg,oldname.get());
  563.                 cfg.save();
  564.                 ret = 0;
  565.                 break;
  566.             }
  567.         }
  568.     }
  569.     return ret;
  570. }
  571.  
  572. static void strcat_b (char *chat, const SSTRING &str)
  573. {
  574.     strcat (chat," ");
  575.     strcat (chat,str.get());
  576. }
  577. /*
  578.     Establish the PPP connection
  579. */
  580. PRIVATE int PPPONE::connect_ppp(int fore)
  581. {
  582.     /* #Specification: ppp / pppd and chat
  583.         All argument to pppd and chat are passed using file
  584.         instead of command line argument. They can't be seen
  585.         using ps -ax.
  586.     */
  587.     char path[PATH_MAX];
  588.     sprintf (path,"%s.%s",f_pppargs.getpath(),name.get());
  589.     FILE *fargs = f_pppargs.fopen (path,"w");
  590.     if (fargs != NULL){
  591.         DAEMON *cmd_chat = daemon_find ("chat");
  592.         DAEMON *cmd_pppd = daemon_find ("pppd");
  593.         if (cmd_chat != NULL && cmd_pppd != NULL){
  594.             char chat[1000];
  595.             strcpy (chat,"ABORT 'NO CARRIER' ABORT BUSY '' ");
  596.             strcat (chat,modeminit.get());
  597.             strcat (chat,phone.get());
  598.             strcat (chat," CONNECT");
  599.             fprintf (fargs,"%s\n",options.get());
  600.             if (!asyncmap.is_empty()){
  601.                 fprintf (fargs,"asyncmap %s\n",asyncmap.get());
  602.             }
  603.             if (type == TYPE_PPP_LOGIN){
  604.                 if (!loginchat.is_empty()){
  605.                     loginchat.copy (chat);
  606.                 }else{
  607.                     strcat (chat," ''");
  608.                     strcat_b (chat,loginkey);
  609.                     strcat_b (chat,login);
  610.                     strcat_b (chat,passwdkey);
  611.                     strcat_b (chat,"\\q");
  612.                     strcat (chat,passwd.get());
  613.                     if (!loginfail.is_empty()){
  614.                         // If we see loginfail, this means that the login
  615.                         // sequence did fail, so we abort right away
  616.                         // instead of falling in pppd and receving all
  617.                         // kind of meaningless messages (pppd believes
  618.                         // it is talking to another pppd).
  619.                         strcat (chat," ABORT");
  620.                         strcat_b (chat,loginfail);
  621.                     }
  622.                     if (!loginok.is_empty()){
  623.                         strcat_b (chat,loginok);
  624.                     }
  625.                 }
  626.             }else if (type == TYPE_PPP_PAP){
  627.                 fprintf (fargs,"+pap user %s\n",login.get());
  628.             }else if (type == TYPE_PPP_CHAP){
  629.                 fprintf (fargs,"+chap user %s\n",login.get());
  630.             }
  631.             if (dbgppp){
  632.                 fputs ("-d -d\n",fargs);
  633.             }
  634.             if (lock) fputs ("lock\n",fargs);
  635.             if (modem){
  636.                 fputs ("modem crtscts\n",fargs);
  637.             }
  638.             fprintf (fargs,"mru %d\n",mru);
  639.             if (mtu != 0) fprintf (fargs,"mtu %d\n",mtu);
  640.             fprintf (fargs,"%s:%s\n",ourip.get(),remoteip.get());
  641.             if (idletime != 0){
  642.                 fprintf (fargs,"idle-disconnect %d\n",idletime);
  643.             }
  644.             if (defaultroute) fputs ("defaultroute\n",fargs);
  645.             if (proxyarp) fputs ("proxyarp\n",fargs);
  646.             if (fore) fputs ("-detach\n",fargs);
  647.             {
  648.                 int d,r;
  649.                 if (lcpecho_parse (d,r)==1){
  650.                     fprintf (fargs,"lcp-echo-interval %d lcp-echo-failure %d\n"
  651.                         ,d,r);
  652.                 }
  653.             }
  654.             char pathchat[PATH_MAX];
  655.             sprintf (pathchat,"%s-chat.%s",f_pppargs.getpath(),name.get());
  656.             FILE *fchat = f_pppargs.fopen (pathchat,"w");
  657.             if (fchat != NULL){
  658.                 fprintf (fargs,"connect '%s %s -f %s'\n"
  659.                     ,cmd_chat->getpath()
  660.                     ,dbgchat ? "-v" : ""
  661.                     ,pathchat);
  662.                 fprintf (fchat,"%s\n",chat);
  663.                 fclose (fchat);
  664.                 fprintf (fargs,"%s\n",device.get());
  665.                 fprintf (fargs,"%d\n",baud);
  666.                 fclose (fargs);
  667.                 dialog_end();
  668.                 fflush (stdout);
  669.                 setuid (geteuid());
  670.                 /* #Specification: netconf / --connect / --fore
  671.                     When connecting a PPP link with the --fore
  672.                     option, linuxconf sleep for 5 seconds
  673.                     before calling pppd. Generally this
  674.                     option is used to establish a permanent
  675.                     link by calling netconf from inittab.
  676.                     The sleep give some chance to the
  677.                     getty/mgetty process to initialise the
  678.                     modem properly before launching another
  679.                     pppd.
  680.  
  681.                     When using the --fore option, netconf
  682.                     just pass control to pppd with the
  683.                     -detach option. netconf does not stay
  684.                     in memory.
  685.                 */
  686.                 if (fore) sleep(5);
  687.                 execl (cmd_pppd->getpath(),cmd_pppd->getpath()
  688.                     ,"file",path,NULL);
  689.             }else{
  690.                 fclose (fargs);
  691.             }
  692.         }
  693.     }
  694.     return -1;
  695. }
  696.  
  697. /*
  698.     Terminate the PPP connection
  699. */
  700. PUBLIC int PPPONE::disconnect_ppp()
  701. {
  702.     /* #Specification: ppp / disconnecting
  703.         The support for disconnection is weak, as it kills
  704.         the first ppp connexion (ppp0) without checking.
  705.         Although this is fine for simple setup, it is not
  706.         acceptable.
  707.  
  708.         We must find a way to get the pid of the pppd process
  709.         and stores it in our own pid file. The problem is that
  710.         pppd fork at one point so we don't know the final
  711.         pid. Maybe an option is needed (or already available)
  712.         in pppd to set the pid file name. This would solve the
  713.         problem.
  714.     */
  715.     int ret = -1;
  716.     FILE *fin = f_ppp0.fopen ("r");
  717.     if (fin != NULL){
  718.         int pid;
  719.         fscanf (fin,"%d",&pid);
  720.         ret = kill (pid,SIGTERM);
  721.         fclose (fin);
  722.     }
  723.     return ret;
  724. }
  725.  
  726. /*
  727.     Initialise a PLIP link
  728. */
  729. PRIVATE int PPPONE::connect_plip()
  730. {
  731.     int ret = -1;
  732.     char buf[100];
  733.     const char *plipdev = type == TYPE_PLIP1 ? "plip1" : "plip2";
  734.     sprintf (buf,"%s %s pointopoint %s",plipdev
  735.         ,ourip.get(),remoteip.get());
  736.     if (netconf_system_if ("ifconfig",buf) != -1){
  737.         sprintf (buf,"add %s %s",remoteip.get(),plipdev);
  738.         if (netconf_system_if ("route",buf) != -1){
  739.             if (!defaultroute){
  740.                 ret = 0;
  741.             }else{
  742.                 sprintf (buf,"add default %s",plipdev);
  743.                 if (netconf_system_if ("route",buf) != -1){
  744.                     ret = 0;
  745.                 }
  746.             }
  747.         }
  748.     }
  749.     return ret;
  750. }
  751. /*
  752.     Terminate a PLIP link
  753. */
  754. PRIVATE int PPPONE::disconnect_plip()
  755. {
  756.     char buf[100];
  757.     const char *plipdev = type == TYPE_PLIP1 ? "plip1" : "plip2";
  758.     sprintf (buf,"%s down",plipdev);
  759.     return netconf_system_if ("ifconfig",buf);
  760. }
  761.  
  762. PRIVATE int PPPONE::connect_slip(int)
  763. {
  764.     xconf_error (MSG_U(E_ONLYPPP,"Only normal PPP is supported yet!"));
  765.     return -1;
  766. }
  767. PRIVATE int PPPONE::disconnect_slip()
  768. {
  769.     xconf_error (MSG_R(E_ONLYPPP));
  770.     return -1;
  771. }
  772. /*
  773.     Establish the PPP/SLIP/PLIP connection
  774. */
  775. PUBLIC int PPPONE::connect(
  776.     int fore)    // Don't go in background
  777. {
  778.     int ret;
  779.     if (type == TYPE_PLIP1 || type == TYPE_PLIP2){
  780.         ret = connect_plip();
  781.     }else if (type == TYPE_SLIP){
  782.         ret = connect_slip(fore);
  783.     }else{
  784.         ret = connect_ppp(fore);
  785.     }
  786.     return ret;
  787. }
  788. /*
  789.     Disconnect the PPP/SLIP/PLIP connection
  790. */
  791. PUBLIC int PPPONE::disconnect()
  792. {
  793.     int ret;
  794.     if (type == TYPE_PLIP1 || type == TYPE_PLIP2){
  795.         ret = disconnect_plip();
  796.     }else if (type == TYPE_SLIP){
  797.         ret = disconnect_slip();
  798.     }else{
  799.         ret = disconnect_ppp();
  800.     }
  801.     return ret;
  802. }
  803. void ppp_edit ()
  804. {
  805.     static const char *msg = MSG_U(P_CONFPPP,"configure PPP and SLIP");
  806.     if (perm_rootaccess(msg)){
  807.         CONFDB cppp (f_ppp);
  808.         int choice = 0;
  809.         while (1){
  810.             SSTRINGS lst;
  811.             int nb = cppp.getall ("",CHANNEL,lst,0);
  812.             lst.sort();
  813.             DIALOG dia;
  814.             for (int i=0; i<nb; i++){
  815.                 dia.new_menuitem (" ",*lst.getitem(i));
  816.             }
  817.             dia.addwhat (MSG_U(I_ADDCONF,"a new configuration"));
  818.             MENU_STATUS code = dia.editmenu(
  819.                 MSG_U(T_PPPCONF,"PPP/SLIP configuration")
  820.                 ,MSG_U(I_PPPCONF,"You are allowed to edit/add\n"
  821.                  "PPP and SLIP configuration\n"
  822.                  "which will allow your computer to connect\n"
  823.                  "to PPP and SLIP server")
  824.                 ,help_ppp
  825.                 ,choice
  826.                 ,0);
  827.             const char *sel = dia.getmenustr(choice);
  828.             if (code == MENU_ESCAPE || code == MENU_QUIT){
  829.                 break;
  830.             }else if (perm_rootaccess(msg)){
  831.                 if (code == MENU_ADD){
  832.                     PPPONE one (cppp,NULL);
  833.                     one.edit (cppp);
  834.                 }else if (sel != NULL){
  835.                     if (code == MENU_OK){
  836.                         PPPONE one (cppp,sel);
  837.                         one.edit (cppp);
  838.                     }
  839.                 }
  840.             }
  841.         }
  842.     }
  843. }
  844.  
  845. static PPPONE *ppp_getconfig (int argc, char *argv[])
  846. {
  847.     PPPONE *ret = NULL;
  848.     if (perm_rootaccess("activate a network link")){
  849.         CONFDB cppp (f_ppp);
  850.         if (argc == 1){
  851.             const char *name = argv[0];
  852.             if (ppp_exist (cppp,name)){
  853.                 ret = new PPPONE (cppp,name);
  854.             }else{
  855.                 xconf_error (MSG_U(E_NOCONF,"No configuration %s"),name);
  856.             }
  857.         }
  858.     }
  859.     return ret;
  860. }
  861.  
  862. /*
  863.     Establish a PPP/SLIP connnection
  864. */
  865. int ppp_connect (int argc, char *argv[])
  866. {
  867.     int ret = -1;
  868.     int fore = 0;
  869.     if (argc == 2){
  870.         argc--;
  871.         if (strcmp(argv[1],"--fore")==0){
  872.             fore = 1;
  873.         }else{
  874.             xconf_error (MSG_U(E_IVLOPTION
  875.                 ,"Invalid option\n"
  876.                  "netconf --connect site [ --fore ]"));
  877.         }
  878.     }
  879.     PPPONE *one = ppp_getconfig (argc,argv);
  880.     if (one != NULL){
  881.         ret = one->connect (fore);
  882.         delete one;
  883.     }
  884.     return ret;
  885. }
  886.  
  887. /*
  888.     Kill a PPP/SLIP connnection
  889. */
  890. int ppp_disconnect (int argc, char *argv[])
  891. {
  892.     int ret = -1;
  893.     PPPONE *one = ppp_getconfig (argc,argv);
  894.     if (one != NULL){
  895.         ret = one->disconnect ();
  896.         delete one;
  897.     }
  898.     return ret;
  899. }
  900.  
  901.